package settings;

import java.io.IOException;
import java.util.*;

import javax.xml.bind.JAXBException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;

//import org.eclipse.jface.viewers.DoubleClickEvent;
import org.xml.sax.SAXException;
import dataStorage.DataXML;
import entity.CashFlow.Period;
import entityManager.*;
import entity.*;
import exception.IllegalInput;
import exception.NullVariableFound;


/**
 * @author A0098808L Yuen Shu Hui
 */
public class MasterController {

	private ExpenseManager em;
	private IncomeManager im;
	private SourceManager sm;
	private CategoryManager cm;
	private GoalManager gm;

	/**
	 * Constructor for Master Controller Class
	 * @author A0098808L Yuen Shu Hui
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public MasterController() throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		em = new ExpenseManager();
		im = new IncomeManager();
		sm = new SourceManager();
		cm = new CategoryManager();
		gm = new GoalManager();
	}

	/**
	 * Initialize all the entity manager classes
	 * @author A0098808L Yuen Shu Hui
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public void init() throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		this.LoadAllManager();
	}

	/**
	 * Load all the objects stored in XML into local storage
	 * @author A0098808L Yuen Shu Hui
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public void LoadAllManager() throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		em.loadAll();
		im.loadAll();
		sm.loadAll();
		cm.loadAll();
		gm.loadAll();
	}

	/**
	 * Get total expenses in the whole system from the beginning of time
	 * @author A0098808L Yuen Shu Hui
	 * @return total expenses in double
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public double GetTotalExpense() throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		return em.getTotalAmount();
	}

	/**
	 * Get total income in the whole system from the beginning of time
	 * @author A0098808L Yuen Shu Hui
	 * @return total income in double
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public double GetTotalIncome() throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		return im.getTotalAmount();
	}

	/**
	 * Get total balance of the whole system from the beginning of time
	 * @author A0098808L Yuen Shu Hui
	 * @return total balance in double
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public double GetTotalBalance() throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		return im.getTotalAmount() - (em.getTotalAmount() + gm.getSavingPot() + gm.CalSavedAmount(gm.getAll()));
	}

	/**
	 * get total expenses in double from a specific date range inclusively
	 * @author A0098808L Yuen Shu Hui
	 * @param _fromDate	
	 * @param _toDate
	 * @return total expense in double
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public double GetTotalExpenseByDateRange(Calendar _fromDate,
			Calendar _toDate) throws TransformerConfigurationException,
			InstantiationException, IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		ArrayList<Expense> temp = em.getByDate(_fromDate, _toDate);
		if (temp.isEmpty())
			throw new NullVariableFound("No Expense with date within "
					+ Settings.getInstance().df.format(_fromDate.getTime())
					+ " - "
					+ Settings.getInstance().df.format(_toDate.getTime())
					+ " can be found.");
		return em.getTotalAmount(temp);
	}

	/**
	 * get a list of expense within the specific date range inclusively
	 * @author A0098808L Yuen Shu Hui
	 * @param _fromDate
	 * @param _toDate
	 * @return list of expense within the date range
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public ArrayList<Expense> GetExpenseListByDateRange(Calendar _fromDate,
			Calendar _toDate) throws TransformerConfigurationException,
			InstantiationException, IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		ArrayList<Expense> temp = em.getByDate(_fromDate, _toDate);
		if (temp.isEmpty())
			throw new NullVariableFound("No Expense with date within "
					+ Settings.getInstance().df.format(_fromDate.getTime())
					+ " - "
					+ Settings.getInstance().df.format(_toDate.getTime())
					+ " can be found.");
		return temp;
	}

	/**
	 * get total income in double from a specific date range inclusively
	 * @author A0098808L Yuen Shu Hui
	 * @param _fromDate	
	 * @param _toDate
	 * @return total income in double
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public double GetTotalIncomeByDateRange(Calendar _fromDate, Calendar _toDate)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		ArrayList<Income> temp = im.getByDate(_fromDate, _toDate);
		if (temp.isEmpty())
			throw new NullVariableFound("No income with date within "
					+ Settings.getInstance().df.format(_fromDate.getTime())
					+ " - "
					+ Settings.getInstance().df.format(_toDate.getTime())
					+ " can be found.");
		return im.getTotalAmount(temp);
	}

	/**
	 * get a list of income within the specific date range inclusively
	 * @author A0098808L Yuen Shu Hui
	 * @param _fromDate
	 * @param _toDate
	 * @return list of income within the date range
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public ArrayList<Income> GetIncomeListByDateRange(Calendar _fromDate,
			Calendar _toDate) throws TransformerConfigurationException,
			InstantiationException, IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		ArrayList<Income> temp = im.getByDate(_fromDate, _toDate);
		if (temp.isEmpty())
			throw new NullVariableFound("No Expense with date within "
					+ Settings.getInstance().df.format(_fromDate.getTime())
					+ " - "
					+ Settings.getInstance().df.format(_toDate.getTime())
					+ " can be found.");
		return temp;
	}

	/**
	 * get total balance of the system within a date range
	 * @author A0098808L Yuen Shu Hui
	 * @param _fromDate
	 * @param _toDate
	 * @return total balance in double
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public double GetTotalBalanceByDateRange(Calendar _fromDate,
			Calendar _toDate) throws TransformerConfigurationException,
			InstantiationException, IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		return this.GetTotalIncomeByDateRange(_fromDate, _toDate)
				- this.GetTotalExpenseByDateRange(_fromDate, _toDate)
				- gm.getSavingPot()
				- gm.CalSavedAmount(gm.getByDate(_fromDate, _toDate));
	}

	/**
	 * get ArrayList of expense of the whole system
	 * @author A0098808L Yuen Shu Hui
	 * @return arrayList of expense
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public ArrayList<Expense> GetAllExpense()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return em.getAll();
	}

	/**
	 * get ArrayList of income of the whole system
	 * @author A0098808L Yuen Shu Hui
	 * @return arrayList of income
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public ArrayList<Income> GetAllIncome()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return im.getAll();
	}

	/**
	 * get ArrayList of source of the whole system
	 * @author A0098808L Yuen Shu Hui
	 * @return arrayList of source
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public ArrayList<Source> GetAllSource()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return sm.getAll();
	}

	/**
	 * get ArrayList of category of the whole system
	 * @author A0098808L Yuen Shu Hui
	 * @return arrayList of category
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public ArrayList<Category> GetAllCategory()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return cm.getAll();
	}

	/**
	 * get ArrayList of goal of the whole system
	 * @author A0098808L Yuen Shu Hui
	 * @return arrayList of goal
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public ArrayList<Goal> GetAllGoal()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return gm.getAll();
	}

	//@author A0105110J
	// Checking Utilities - Defensive code
	private Category CategoryCheck(String _category)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		Category tempCategory = null;

		if (cm.getByName(_category) == null) {
			cm.add(new Category(_category));
		}

		tempCategory = cm.getByName(_category);

		return tempCategory;
	}

	//@author A0105110J
	private Source SourceCheck(String _source)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		Source tempSource = null;

		if (sm.getByName(_source) == null) {
			sm.add(new Source(_source));
		}
		tempSource = sm.getByName(_source);

		return tempSource;
	}

	/**
	 * validate the input amount is a valid value
	 * @author A0098808L Yuen Shu Hui
	 * @param _amount
	 * @return the inout amount in 2 decimal point
	 * @throws IllegalInput
	 */
	private double AmountCheck(double _amount) throws IllegalInput {
		if (_amount < 0.00) {
			throw new IllegalInput("Amount cannot be less than $0.00");
		} else
			return new Double(Settings.doubleTo2DP(_amount));
	}

	// end of Checking Utilities

	// Misc Utilities
	/**
	 * simple print function to print any list given
	 * @author A0098808L Yuen Shu Hui
	 * @param _input
	 */
	public void PrintList(ArrayList _input) {
		Iterator lt = _input.iterator();
		while (lt.hasNext()) {
			System.out.println(lt.next().toString());
		}
	}

	/**
	 * Sorting Utility to sort the input expense list into descending order
	 * @author A0098808L Yuen Shu Hui
	 * @param _list
	 */
	public void SortExpenseListInDescendingOrder(ArrayList<Expense> _list) {
		em.SortListDescendingDate(_list);
	}

	/**
	 * Sorting Utility to sort the input expense list into ascending order
	 * @author A0098808L Yuen Shu Hui
	 * @param _list
	 */
	public void SortExpenseListInAscendingOrder(ArrayList<Expense> _list) {
		em.SortListAscendingDate(_list);
	}

	/**
	 * Sorting Utility to sort the input Income list into descending order
	 * @author A0098808L Yuen Shu Hui
	 * @param _list
	 */
	public void SortIncomeListInDescendingOrder(ArrayList<Income> _list) {
		im.SortListDescendingDate(_list);
	}

	/**
	 * Sorting Utility to sort the input income list into ascending order
	 * @author A0098808L Yuen Shu Hui
	 * @param _list
	 */
	public void SortIncomeListInAscendingOrder(ArrayList<Income> _list) {
		im.SortListAscendingDate(_list);
	}

	public void Undo() throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		DataXML.getInstance().Undo();
	}

	// end of MISC utilities


	// Functions for Expense
	/**
	 * Add Expense into the system, handle by expense Manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _name
	 * @param _category
	 * @param _amount
	 * @param _source
	 * @param _date
	 * @param _isRecurs
	 * @param _recursPeriod
	 * @param _recursParentId
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws IllegalInput
	 */
	public void AddExpense(String _name, String _category, double _amount,
			String _source, Calendar _date, Boolean _isRecurs,
			Period _recursPeriod, String _recursParentId)
					throws TransformerConfigurationException, InstantiationException,
					IllegalAccessException, JAXBException,
					ParserConfigurationException, SAXException, IOException,
					TransformerException, IllegalInput {
		em.add(this.CreateExpense(_name, _category, _amount, _source, _date,
				_isRecurs, _recursPeriod, _recursParentId));
	}

	/**
	 * Create a new expense object and validate all the input fields
	 * @author A0098808L Yuen Shu Hui
	 * @param _name
	 * @param _category
	 * @param _amount
	 * @param _source
	 * @param _date
	 * @param _isRecurs
	 * @param _recursPeriod
	 * @param _recursParentId
	 * @return a new expense object
	 * @throws IllegalInput
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	private Expense CreateExpense(String _name, String _category,
			double _amount, String _source, Calendar _date, Boolean _isRecurs,
			Period _recursPeriod, String _recursParentId) throws IllegalInput,
			TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return new Expense(_name, CategoryCheck(_category),
				AmountCheck(_amount), SourceCheck(_source), _date, _isRecurs,
				_recursPeriod, _recursParentId);
	}

	/**
	 * remove expense handle by expense manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public boolean RemoveExpense(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		Expense temp = em.getById(_id);
		if (temp != null)
			return em.remove(temp);
		else
			throw new NullVariableFound("No existing Expense entry with ID of "
					+ _id);
	}

	/**
	 * update the expense 
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @param _name
	 * @param _category
	 * @param _amount
	 * @param _source
	 * @param _date
	 * @param _isRecurs
	 * @param _recursPeriod
	 * @param _recursParentId
	 * @return true if the expense is being removed, false if the expense is not exist
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalInput
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public boolean UpdateExpense(String _id, String _name, String _category,
			double _amount, String _source, Calendar _date, Boolean _isRecurs,
			Period _recursPeriod, String _recursParentId)
					throws TransformerConfigurationException, InstantiationException,
					IllegalAccessException, IllegalInput, JAXBException,
					ParserConfigurationException, SAXException, IOException,
					TransformerException, NullVariableFound {
		if (em.getById(_id) == null) {
			throw new NullVariableFound("No existing Expense entry with ID of "
					+ _id);
		} else {
			// create an empty dummy placeholder without increment the id
			Expense temp = this.CreateExpense(_name, _category, _amount, _source, _date, _isRecurs, _recursPeriod, _recursParentId);
			temp.setId(_id);
			return em.update(temp);
		}
	}

	/**
	 * Get list of expense with the input keyword
	 * @author A0098808L Yuen Shu Hui
	 * @param _keyword
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public ArrayList<Expense> GetExpenseByKeyword(String _keyword)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		ArrayList<Expense> temp = em.getByKeyword(_keyword);
		if (temp.size() > 0) {
			return temp;
		} else
			throw new NullVariableFound(
					"There is no existing expense with keyword of " + _keyword);
	}

	/**
	 * Get list of recursive expense
	 * @author A0098808L Yuen Shu Hui	
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 * @throws IllegalInput
	 */
	public ArrayList<Expense> GetRecursExpense()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound, IllegalInput {
		ArrayList<Expense> temp = em.getRecursExpense();
		if (temp.size() > 0) {
			return temp;
		} else
			throw new NullVariableFound("There is no recursive expense found.");
	}

	/**
	 * Handle recursive expenses by expense manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _date
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 * @throws IllegalInput
	 */
	public void HandleRecursExpense(Calendar _date)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound, IllegalInput {
		em.HandleRecursList(_date);
	}

	/**
	 * get an unique expense object by its id
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public Expense GetExpenseById(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return em.getById(_id);
	}

	/**
	 * get a total expense of all the expense with same category
	 * @author A0098808L Yuen Shu Hui
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public Map<String, Double> GetTotalExpenseByCategory()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		Map<String, Double> totalExpenseMap = new TreeMap<String, Double>();

		Category temp;
		Iterator<Category> lt = cm.getAll().iterator();
		while (lt.hasNext()) {
			temp = lt.next();
			double currSum = em.getTotalAmountByList(em.getByCategory(temp));
			totalExpenseMap.put(temp.getName(), currSum);
			currSum = 0d;
		}
		return totalExpenseMap;
	}

	/**
	 * get a total expense of all the expense with same source
	 * @author A0098808L Yuen Shu Hui
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public Map<String, Double> GetTotalExpenseBySource()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		Map<String, Double> totalExpenseMap = new TreeMap<String, Double>();

		Source temp;
		Iterator<Source> lt = sm.getAll().iterator();
		while (lt.hasNext()) {
			temp = lt.next();
			double currSum = em.getTotalAmountByList(em.getBySource(temp));
			totalExpenseMap.put(temp.getName(), currSum);
		}
		return totalExpenseMap;
	}



	// Functions for Income
	/**
	 * Add Income into the system, handle by income Manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _name
	 * @param _category
	 * @param _amount
	 * @param _source
	 * @param _date
	 * @param _isRecurs
	 * @param _recursPeriod
	 * @param _recursParentId
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws IllegalInput
	 */
	public void AddIncome(String _name, String _category, double _amount,
			String _source, Calendar _date, Boolean _isRecurs,
			Period _recursPeriod, String _recursParentId)
					throws TransformerConfigurationException, InstantiationException,
					IllegalAccessException, JAXBException,
					ParserConfigurationException, SAXException, IOException,
					TransformerException, IllegalInput {
		im.add(this.CreateIncome(_name, _category, _amount, _source, _date,
				_isRecurs, _recursPeriod, _recursParentId));
	}

	/**
	 * Create a new income object and validate all the input fields
	 * @author A0098808L Yuen Shu Hui
	 * @param _name
	 * @param _category
	 * @param _amount
	 * @param _source
	 * @param _date
	 * @param _isRecurs
	 * @param _recursPeriod
	 * @param _recursParentId
	 * @return a new expense object
	 * @throws IllegalInput
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	private Income CreateIncome(String _name, String _category, double _amount,
			String _source, Calendar _date, Boolean _isRecurs,
			Period _recursPeriod, String _recursParentId) throws IllegalInput,
			TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return new Income(_name, CategoryCheck(_category),
				AmountCheck(_amount), SourceCheck(_source), _date, _isRecurs,
				_recursPeriod, _recursParentId);
	}

	/**
	 * remove income handle by expense manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public boolean RemoveIncome(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		Income temp = im.getById(_id);
		if (temp != null)
			return im.remove(temp);
		else
			throw new NullVariableFound("No existing Income entry with ID of "
					+ _id);
	}

	/**
	 * update the income 
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @param _name
	 * @param _category
	 * @param _amount
	 * @param _source
	 * @param _date
	 * @param _isRecurs
	 * @param _recursPeriod
	 * @param _recursParentId
	 * @return true if the expense is being removed, false if the expense is not exist
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws IllegalInput
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public boolean UpdateIncome(String _id, String _name, String _category,
			double _amount, String _source, Calendar _date, Boolean _isRecurs,
			Period _recursPeriod, String _recursParentId)
					throws TransformerConfigurationException, InstantiationException,
					IllegalAccessException, IllegalInput, JAXBException,
					ParserConfigurationException, SAXException, IOException,
					TransformerException, NullVariableFound {
		if (im.getById(_id) == null) {
			throw new NullVariableFound("No existing Income entry with ID of "
					+ _id);
		} else {
			// create an empty dummy placeholder without increment the id
			Income temp = this.CreateIncome(_name, _category, _amount, _source, _date, _isRecurs, _recursPeriod, _recursParentId);
			temp.setId(_id);
			return im.update(temp);
		}
	}

	/**
	 * Get list of income with the input keyword
	 * @author A0098808L Yuen Shu Hui
	 * @param _keyword
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public ArrayList<Income> GetIncomeByKeyword(String _keyword)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		ArrayList<Income> temp = im.getByKeyword(_keyword);
		if (temp.size() > 0) {
			return temp;
		} else
			throw new NullVariableFound(
					"There is no existing income with keyword of " + _keyword);
	}

	/**
	 * Get list of recursive income
	 * @author A0098808L Yuen Shu Hui	
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 * @throws IllegalInput
	 */
	public ArrayList<Income> GetRecursIncome()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound, IllegalInput {
		ArrayList<Income> temp = im.getRecursIncome();
		if (temp.size() > 0) {
			return temp;
		} else
			throw new NullVariableFound("There is no recursive income found.");
	}

	/**
	 * Handle recursive Income by expense manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _date
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 * @throws IllegalInput
	 */
	public void HandleRecursIncome(Calendar _date)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound, IllegalInput {
		im.HandleRecursList(_date);
	}

	/**
	 * get an unique income object by its id
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public Income GetIncomeById(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return im.getById(_id);
	}

	/**
	 * get a total expense of all the Income with same category
	 * @author A0098808L Yuen Shu Hui
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public Map<String, Double> GetTotalIncomeByCategory()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		Map<String, Double> totalIncomeMap = new TreeMap<String, Double>();

		Category temp;
		Iterator<Category> lt = cm.getAll().iterator();
		while (lt.hasNext()) {
			temp = lt.next();
			double currSum = im.getTotalAmountByList(im.getByCategory(temp));
			totalIncomeMap.put(temp.getName(), currSum);
		}
		return totalIncomeMap;
	}

	/**
	 * get a total expense of all the income with same source
	 * @author A0098808L Yuen Shu Hui
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public Map<String, Double> GetTotalIncomeBySource()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		Map<String, Double> totalIncomeMap = new TreeMap<String, Double>();

		Source temp;
		Iterator<Source> lt = sm.getAll().iterator();
		while (lt.hasNext()) {
			temp = lt.next();
			double currSum = im.getTotalAmountByList(im.getBySource(temp));
			totalIncomeMap.put(temp.getName(), currSum);
		}
		return totalIncomeMap;
	}



	//@author A0105110J
	// Functions for Source
	public void AddSource(String _name)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, IOException, JAXBException,
			ParserConfigurationException, SAXException, TransformerException {
		sm.add(this.CreateSource(_name));
	}

	public Source CreateSource(String _name)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return SourceCheck(_name);
	}

	public boolean RemoveSource(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		Source temp = sm.getById(_id);
		if (temp != null)
			return sm.remove(temp);
		else
			throw new NullVariableFound("No existing Source entry with ID of "
					+ _id);
	}

	public boolean UpdateSource(String _id, String _name)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, IOException, JAXBException,
			ParserConfigurationException, SAXException, TransformerException,
			NullVariableFound {

		if (sm.getById(_id) == null) {
			throw new NullVariableFound("No existing Expense entry with ID of "
					+ _id);
		} else {
			Source temp = new Source(); // create an empty dummy placeholder
			// without increment the id
			temp.setName(_name);
			temp.setId(_id);
			return sm.update(temp);
		}
	}

	public Source GetSourceByName(String _keyword)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		Source temp = sm.getByName(_keyword);
		if (temp != null) {
			return temp;
		} else
			throw new NullVariableFound(
					"There is no existing category with keyword of " + _keyword);
	}

	// Functions for Category
	public void AddCategory(String _name)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, IOException, JAXBException,
			ParserConfigurationException, SAXException, TransformerException {
		cm.add(this.CreateCategory(_name));
	}

	//@author A0105110J
	// redundant
	// there is a category check up there
	public Category CreateCategory(String _name)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return new Category(_name);
	}

	public boolean RemoveCategory(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		Category temp = cm.getById(_id);
		if (temp != null)
			return cm.remove(temp);
		else
			throw new NullVariableFound(
					"No existing Category entry with ID of " + _id);
	}

	public boolean UpdateCategory(String _id, String _name)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, IOException, JAXBException,
			ParserConfigurationException, SAXException, TransformerException,
			NullVariableFound {

		if (cm.getById(_id) == null) {
			throw new NullVariableFound(
					"No existing Category entry with ID of " + _id);
		} else {
			Category temp = new Category(); // create an empty dummy placeholder
			// without increment the id
			temp.setName(_name);
			temp.setId(_id);
			return cm.update(temp);
		}
	}

	public Category GetCategoryByName(String _keyword)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		Category temp = cm.getByName(_keyword);
		if (temp != null) {
			return temp;
		} else
			throw new NullVariableFound(
					"There is no existing expense with keyword of " + _keyword);
	}

	// Functions for Goal
	/**
	 * Add a new goal to the system, handle by Goal Manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _name
	 * @param _startDate
	 * @param _endDate
	 * @param _totalAmt
	 * @param _amtAchieved
	 * @param _comment
	 * @param _isActive
	 * @param _achieved
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws IllegalInput
	 */
	public void AddGoal(String _name, Calendar _startDate, Calendar _endDate,
			double _totalAmt, double _amtAchieved, String _comment,
			boolean _isActive, boolean _achieved)
					throws TransformerConfigurationException, InstantiationException,
					IllegalAccessException, JAXBException,
					ParserConfigurationException, SAXException, IOException,
					TransformerException, IllegalInput {
		Goal temp = this.CreateGoal(_name, _startDate, _endDate, _totalAmt,
				_amtAchieved, _comment, _isActive, _achieved);
		gm.add(temp);
	}

	/**
	 * Create a new Goal object using parameter given and validate amount fields
	 * @author A0098808L Yuen Shu Hui
	 * @param _name
	 * @param _startDate
	 * @param _endDate
	 * @param _totalAmt
	 * @param _amtAchieved
	 * @param _comment
	 * @param _isActive
	 * @param _achieved
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws IllegalInput
	 */
	private Goal CreateGoal(String _name, Calendar _startDate,
			Calendar _endDate, double _totalAmt, double _amtAchieved,
			String _comment, boolean _isActive, boolean _achieved)
					throws TransformerConfigurationException, InstantiationException,
					IllegalAccessException, JAXBException,
					ParserConfigurationException, SAXException, IOException,
					TransformerException, IllegalInput {
		return new Goal(_name, _startDate, _endDate,
				this.AmountCheck(_totalAmt), this.AmountCheck(_amtAchieved),
				_comment, _isActive, _achieved);
	}

	/**
	 * Remove goal object from the system. Handle by goal Manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public boolean RemoveGoal(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		return gm.remove(this.GetGoalById(_id));
	}

	/**
	 * Update a goal entry. Handle by Goal Manager
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @param _name
	 * @param _startDate
	 * @param _endDate
	 * @param _totalAmt
	 * @param _amtAchieved
	 * @param _comment
	 * @param _isActive
	 * @param _achieved
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 * @throws IllegalInput
	 */
	public boolean UpdateGoal(String _id, String _name, Calendar _startDate,
			Calendar _endDate, double _totalAmt, double _amtAchieved,
			String _comment, boolean _isActive, boolean _achieved)
					throws TransformerConfigurationException, InstantiationException,
					IllegalAccessException, JAXBException,
					ParserConfigurationException, SAXException, IOException,
					TransformerException, NullVariableFound, IllegalInput {
		if (gm.getById(_id) == null) {
			throw new NullVariableFound("No existing Goal entry with ID of "
					+ _id);
		} else {
			// create an empty dummy placeholder without increment the id
			Goal temp = this.CreateGoal(_name, _startDate, _endDate, _totalAmt,
					_amtAchieved, _comment, _isActive, _achieved); 
			temp.setId(_id);
			gm.checkUpdate(temp);
			return gm.update(temp);
		}
	}

	/**
	 * Get a specific goal using its id
	 * @author A0098808L Yuen Shu Hui
	 * @param _id
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 * @throws NullVariableFound
	 */
	public Goal GetGoalById(String _id)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException, NullVariableFound {
		Goal temp = gm.getById(_id);
		if (temp != null)
			return temp;
		else
			throw new NullVariableFound("No existing Goal entry with ID of "
					+ _id);
	}

	/**
	 * get a list of goal with the input keyword
	 * @author A0098808L Yuen Shu Hui
	 * @param _keyword
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public ArrayList<Goal> GetGoalByKeyword(String _keyword)
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return gm.getByKeyword(_keyword);
	}

	/**
	 * get a list of active goal
	 * @author A0098808L Yuen Shu Hui
	 * @return
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public ArrayList<Goal> GetActiveGoal()
			throws TransformerConfigurationException, InstantiationException,
			IllegalAccessException, JAXBException,
			ParserConfigurationException, SAXException, IOException,
			TransformerException {
		return gm.getActiveGoal();
	}

	/**
	 * Initialize saving pot by the system (only call in init function)
	 * @author A0098808L Yuen Shu Hui
	 * @param _amount
	 */
	public void InitializeSavingPot(double _amount) {
		gm.setSavingPot(_amount);
	}

	/**
	 * deposit input amount into saving Pot (manually deposit by user)
	 * @author A0098808L Yuen Shu Hui
	 * @param _amount
	 */
	public void DepositToSavingPot(double _amount) {
		gm.depositSavingPot(_amount);
	}

	/**
	 * Adjust to save amount (manually change by user)
	 * @author A0098808L Yuen Shu Hui
	 * @param _amount
	 */
	public void AdjustToSaveAmount(double _amount) {
		gm.setToSaveAmt(_amount);
	}

	/**
	 * Handle Distribution of fund from saving pot to each goal (perform recursively by system)
	 * @author A0098808L Yuen Shu Hui
	 * @param today
	 * @throws TransformerConfigurationException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws TransformerException
	 */
	public void HandleGoal(Calendar _today) throws TransformerConfigurationException,
	InstantiationException, IllegalAccessException, JAXBException,
	ParserConfigurationException, SAXException, IOException,
	TransformerException {
		// validate balance
		if (this.GetTotalBalance() > gm.getToSaveAmt())
			gm.depositSavingPot(gm.getToSaveAmt());

		if (gm.getSavingPot() <= 0){
			gm.deactivateAllGoal();
			System.out.println("insufficient fund to perform handle goal. All goal has been deactivated");
		}
		else {
			gm.ActivateDisableGoal(_today);
			gm.HandleGoal();
		} 

	}

	/**
	 * Get amount available in saving pot, handle by goal manager
	 * @author A0098808L Yuen Shu Hui
	 * @return
	 */
	public double GetSavingPotAmount() {
		return gm.getSavingPot();
	}

	/**
	 * get To save amount from saving pot, handle by goal manager
	 * @author A0098808L Yuen Shu Hui
	 * @return
	 */
	public double GetToSaveAmount() {
		return gm.getToSaveAmt();
	}

}
